﻿'-------------------------------------------------------------------------------
'Developer: Ivan Tamurejo
'-------------------------------------------------------------------------------
'This class allows you to send emails through SMTP. You can send attachments and
'connect to servers with secure connections.
'-------------------------------------------------------------------------------

Imports System.Net.Mail
Imports System.Net.Mime
Imports System.IO
Imports System.Reflection.Assembly

Public Class EMail

#Region "Public class variables to configure and send email"

    Public UserID As String 'Identifier for the user account to send the email
    Public UserPass As String 'The user account password to send the email
    Public ServerSMTP As String 'Mail (SMTP) Server
    Public PortSMTP As Integer 'Port for sending mails
    Public UserNameSend As String '(Optional) Name that will be displayed as sent mail user
    Public RespondingTo As String 'E-Mail who must respond
    Public Recipients As String 'E-Mail recipients
    Public SecureConnection As Boolean  '(Optional) Indicates if connecting to a server with secure connection or not
    Public MessageDescription As String 'Description of the message to send
    Public MessageContentPlainText As String 'The message content for mail clients that do not interpret HTML
    Public MessageContentHTMLText As String 'The message content for mail clients that support HTML
    Public PathAttachment1 As String 'Path of the first attachment file, if empty not is added the file
    Public PathAttachment2 As String 'Path to the second attachment file, if empty not is added the file
    Public PathAttachment3 As String 'Path of the third attachment file, if empty not is added the file
    Public PathCorporateImage As String  'Corporate image which will be embedded in the message body file path

#End Region

#Region "Properties for the class error handling"

    'Control de Errores
    '--------------------------------------------------------------------------
    Private _errID As Integer
    Public ReadOnly Property errID() As Integer
        Get
            Return _errID
        End Get
    End Property

    Private _errDescription As String
    Public ReadOnly Property errDescription() As String
        Get
            Return _errDescription
        End Get
    End Property
    '--------------------------------------------------------------------------

#End Region

#Region "Private variables"

    'Variables internas
    '--------------------------------------------------------------------------
    Private tRecipients() As String 'Variable interna para controlar el número de destinos
    Private bDisposed As Boolean
    Private Message As MailMessage
    Private Sender As SmtpClient
    Private Credential As System.Net.NetworkCredential
    '--------------------------------------------------------------------------

#End Region

#Region "Procedures -New- and -Finalize-"

    Sub New()

        Try

            ServerSMTP = IniGet(PathINI, "EMAIL", "ServerSMTP")
            If IniGet(PathINI, "EMAIL", "PortSMTP") = "" Then
                PortSMTP = 25
            Else
                PortSMTP = CType(IniGet(PathINI, "EMAIL", "PortSMTP"), Integer)
            End If
            UserID = IniGet(PathINI, "EMAIL", "UserID")
            UserPass = EncryptString(IniGet(PathINI, "EMAIL", "UserPass"), "D")
            SecureConnection = (IniGet(PathINI, "EMAIL", "SecureConnection") = "1")
            RespondingTo = IniGet(PathINI, "EMAIL", "RespondingTo")
            If IniGet(PathINI, "EMAIL", "UserNameSend") = "" Then
                UserNameSend = "RobotBuilds"
            Else
                UserNameSend = IniGet(PathINI, "EMAIL", "UserNameSend")
            End If
            

        Catch ex As Exception

            Throw New Exception(ex.Message)

        End Try

    End Sub

    Public Sub Dispose()

        Finalize()

    End Sub

    Protected Overrides Sub Finalize()
        MyBase.Finalize()

        If Not bDisposed Then

            If Not Message Is Nothing Then Message = Nothing
            If Not Sender Is Nothing Then Sender = Nothing
            If Not Credential Is Nothing Then Credential = Nothing
            bDisposed = True

        End If

    End Sub


#End Region

#Region "Functions for sending, configuration and validations"

    'Function for sending e-mails or notifications.
    'You construct the message to send.
    Public Function Send() As Boolean
        Dim iMailAddress As Integer

        'Before sending, check the configuration data is correct.
        If CheckingEmail() Then

            Message = New MailMessage

            If UserNameSend = "" Then

                Message.From = New MailAddress(UserID)
                If RespondingTo <> "" Then Message.ReplyTo = New MailAddress(RespondingTo)

            Else

                Message.From = New MailAddress(UserID, UserNameSend)
                If RespondingTo <> "" Then Message.ReplyTo = New MailAddress(RespondingTo, UserNameSend)

            End If

            For iMailAddress = 0 To tRecipients.Length - 1

                Message.To.Add(tRecipients(iMailAddress).ToString)

            Next iMailAddress

            Message.Subject = MessageDescription

            'View of the message in plain text. COMPULSORY
            '----------------------------------------------------------------------------------------------------------------
            'We create the view for clients that can only access plain text...
            Dim plainView As AlternateView = AlternateView.CreateAlternateViewFromString(MessageContentPlainText, System.Text.Encoding.UTF8, MediaTypeNames.Text.Plain)
            'We link the plain text view.
            Message.AlternateViews.Add(plainView)
            '----------------------------------------------------------------------------------------------------------------

            'View the message in text HTML if applicable. OPTIONAL
            '----------------------------------------------------------------------------------------------------------------
            If MessageContentHTMLText <> "" Then

                'Add space for the signing of the message if you have indicated an image file
                If PathCorporateImage <> "" Then
                    MessageContentHTMLText += "<br><img src='cid:imagen' />"
                End If

                'Now create the view for clients that can display HTML content... OPTIONAL
                Dim htmlView As AlternateView = AlternateView.CreateAlternateViewFromString(MessageContentHTMLText, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html)

                'We create the resource to embed. Observe that the ID assign (arbitrary) is referenced from the HTML code as 
                'image source. Only embedded image, in the case having defined their Path.
                If PathCorporateImage <> "" Then

                    Try

                        Dim img As LinkedResource = New LinkedResource(PathCorporateImage, MediaTypeNames.Image.Jpeg)
                        img.ContentId = "image"
                        'We include the image in HTML view.
                        htmlView.LinkedResources.Add(img)

                    Catch Ex As Exception

                        _errID = -9
                        _errDescription = "Error loading corporate image: " & Ex.Message
                        Return False

                    End Try


                End If

                'We link the text in HTML view.
                Message.AlternateViews.Add(htmlView)

            End If
            '----------------------------------------------------------------------------------------------------------------

            Sender = New SmtpClient(ServerSMTP, PortSMTP)
            Credential = New System.Net.NetworkCredential(UserID, UserPass)

            'Needless to indicate this property as it now ván two views in the message one is in
            'plain text and another in html text.
            'Message.Body = MessageContents
            'Message.IsBodyHtml = true

            Message.Priority = MailPriority.High

            If PathAttachment1 <> "" Then Message.Attachments.Add((New Attachment(PathAttachment1)))
            If PathAttachment2 <> "" Then Message.Attachments.Add((New Attachment(PathAttachment2)))
            If PathAttachment3 <> "" Then Message.Attachments.Add((New Attachment(PathAttachment3)))

            Sender.UseDefaultCredentials = False
            Sender.Credentials = Credential
            Sender.EnableSsl = SecureConnection

            Return SendMail()

        Else

            Return False

        End If

    End Function

    'Function that sends the message built by e-mail.
    Private Function SendMail() As Boolean

        Try

            Sender.Send(Message)
            _errID = 0
            _errDescription = "The e-mail has been sent."
            Return True

        Catch Ex As Exception

            _errID = -1000
            _errDescription = Ex.Message

        Finally

            Message = Nothing
            Sender = Nothing
            Credential = Nothing

        End Try

    End Function

    'Function check if it is possible to submit before.
    Private Function CheckingEmail() As Boolean
        Dim iMailAddress As Integer

        _errID = 0
        _errDescription = ""

        Try

            If (Not ValidateEmail(UserID)) Then
                'The specified user ID is invalid, must be of type "name@server.com"
                _errID = -1
                _errDescription = "The specified user ID is invalid, must be of type 'Name@Server.com'."
                Return False
            End If

            If UserPass = "" Then
                'It is necessary to indicate a valid password to connect to the mail server.
                _errID = -2
                _errDescription = "It is necessary to indicate a valid password to connect to the mail server."
                Return False
            End If

            If ServerSMTP = "" Then
                'It is necessary to indicate an outgoing mail (SMTP) Server
                _errID = -3
                _errDescription = "It is necessary to indicate an outgoing mail (SMTP) server."
                Return False
            End If

            'It is not compulsory.
            If RespondingTo <> "" Then

                If (Not ValidateEmail(RespondingTo)) Then
                    'The e-mail address indicated in case of response does not comply with validations of valid e-mail.
                    _errID = -4
                    _errDescription = "The e-mail address indicated in case of response does not comply with validations of valid e-mail."
                    Return False

                End If

            End If

            tRecipients = GetRecipients(Recipients)
            If tRecipients.Length = 0 Then
                'Have not indicated destination emails
                _errID = -5
                _errDescription = "Destination e-mails have not indicated."
            End If

            For iMailAddress = 0 To tRecipients.Length - 1

                If Not ValidateEmail(tRecipients(iMailAddress).ToString) Then

                    'Some e-mail indicated as the mail destination does not meet validations valid email
                    _errID = -6
                    _errDescription = "The e-mail address indicated as the target of mail '" & tRecipients(iMailAddress).ToString & "' does not comply with valid e-mail validations."
                    Return False

                End If

            Next iMailAddress

            If MessageDescription = "" Then
                'It is necessary to indicate a description to the message to send it.
                _errID = -7
                _errDescription = "It is necessary to indicate a description to the message to send it."
                Return False
            End If

            If MessageContentPlainText = "" Then

                _errID = -8
                _errDescription = "It is necessary to indicate the message in plain text content to be able to send."
                Return False

            End If


            'If you terminate, then validations connection are valid.
            Return True

        Catch ex As Exception

            _errID = -1000
            _errDescription = "An unexpected error has occurred to validate the connection: " & ex.Message & "."
            Return False

        End Try

    End Function

    'Checks whether an e-mail meet the requirements of an e-mail.
    Private Function ValidateEmail(ByVal Email As String) As Boolean

        If ((Email.IndexOf("@") <> Email.LastIndexOf("@")) Or Email.IndexOf("@") = -1) Then Return False

        If (Email(Email.IndexOf("@") + 1) = ".") Then Return False

        If ((Email.LastIndexOf(".") = Email.Length - 1) Or Email.LastIndexOf(".") = -1) Then Return False

        If (Email.Contains(" ") Or Email.Contains("\\") Or Email.Contains("/") Or Email.Contains("*") Or Email.Contains(";")) Then Return False

        Return True

    End Function

    'This function gets different recipients separated by ";" and introduces in the 
    'internal recipients vector.
    Private Function GetRecipients(ByVal sRecipients As String) As String()
        Dim tRecipients() As String
        Dim lRecipients As New List(Of String)
        Dim iMailAddress As Integer

        tRecipients = Split(sRecipients, ";")

        For iMailAddress = 0 To tRecipients.Length - 1

            If Trim(tRecipients(iMailAddress)) <> "" Then

                lRecipients.Add(tRecipients(iMailAddress))

            End If

        Next iMailAddress


        Return lRecipients.ToArray

    End Function

#End Region

End Class
